package com.zf.thread_pool.thread_first;

import com.zf.thread_pool.ExecutorManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义优先创建线程的线程池，新任务进入时，首先去“获取已有/创建新的”线程，直到线程数量达到 "maximumPoolSize"。
 * 当无法再创建新的线程时再将任务加入工作队列
 */
public class CustomThreadFirstPool {
    public static Logger log = LoggerFactory.getLogger(CustomThreadFirstPool.class);

    /**
     * 此类型线程池的实例名称的前缀
     */
    private static final String THREAD_POOL_NAME_PREFIX = "thread-first-pool-";
    /**
     * 此类型线程池的实例数量
     */
    private static final AtomicInteger THREAD_POOL_INSTANCE_NUMBER = new AtomicInteger(0);

    /**
     * 创建一个默认参数的线程优先的线程池实例
     *
     * @param printPoolStatus 是否定时打印线程池的状态
     */
    public static ThreadPoolExecutor getDefaultThreadFirstPool(boolean printPoolStatus) {
        // 逻辑处理器的数量
        int availableProcessorNum = Runtime.getRuntime().availableProcessors() - 1;
        // 创建线程优先线程池，定时打印线程池的状态信息
        return buildThreadFirstPool(
                availableProcessorNum,
                availableProcessorNum * 4,
                5, TimeUnit.MINUTES,
                1 << 16,
                printPoolStatus
        );
    }

    /**
     * 构建一个线程优先线程池
     *
     * @param corePoolSize    核心线程数
     * @param maximumPoolSize 最大线程数
     * @param keepAliveTime   空闲时间，超过核心线程数量的其他的线程，在空闲超过此时间后，线程被销毁
     * @param unit            空闲时间单位
     * @param workQueueSize   工作队列的大小
     * @param printPoolStatus 是否定时打印线程池的状态
     */
    public static ThreadPoolExecutor buildThreadFirstPool(
            int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            Integer workQueueSize,
            boolean printPoolStatus) {

        // 线程池的名字
        String threadPoolName = THREAD_POOL_NAME_PREFIX + THREAD_POOL_INSTANCE_NUMBER.incrementAndGet();

        // 创建线程优先线程池，通过自定义的 “工作队列 和 拒绝策略” 来实现
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize, // 核心线程数
                maximumPoolSize,// 最大线程数
                keepAliveTime, unit, // 超过核心线程数量的其他的线程，在空闲超过此时间后，线程被销毁
                new CustomThreadFirstWorkQueue(workQueueSize),  // 工作队列
                new CustomThreadFactory(threadPoolName), // 线程工厂
                new CustomThreadFirstRejectedPolicy() //拒绝策略
        );

        // 给JVM进程添加关闭时的回调，当JVM进程关闭时 优雅的关闭线程池
        Runtime.getRuntime().addShutdownHook(new Thread(executor::shutdown));

        // 是否定时打印线程池的状态
        if (printPoolStatus) {
            ExecutorManager.printPoolStatusAtFixedRate(executor, threadPoolName, 1000, TimeUnit.MILLISECONDS);
        }

        // 返回创建的线程池
        return executor;
    }
}
